// Package dedup provides deduplication engine interfaces and implementations
package dedup

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"hash"
	"os"
	"path/filepath"
	"sync"

	"github.com/smart-snapshotter/pkg/types"
	"github.com/zeebo/blake3"
)

// Engine represents a deduplication engine interface
type Engine interface {
	// File-level deduplication
	AddFile(ctx context.Context, path string, data []byte) (string, error)
	GetFile(ctx context.Context, hash string) ([]byte, error)
	DeleteFile(ctx context.Context, hash string) error
	DeleteFileByPath(ctx context.Context, path string) error
	FileExists(ctx context.Context, hash string) (bool, error)

	// Block-level deduplication
	AddBlock(ctx context.Context, data []byte) (string, error)
	GetBlock(ctx context.Context, hash string) ([]byte, error)
	DeleteBlock(ctx context.Context, hash string) error
	BlockExists(ctx context.Context, hash string) (bool, error)

	// Block processing
	ProcessBlocks(ctx context.Context, data []byte) ([]BlockInfo, error)
	ReconstructFile(ctx context.Context, blocks []BlockInfo) ([]byte, error)

	// Snapshot processing
	ProcessSnapshot(ctx context.Context, snapshotID string, path string) error
	RemoveSnapshot(ctx context.Context, snapshotID string) error
	GetSnapshotUsage(ctx context.Context, snapshotID string) (StorageUsage, error)

	// Statistics
	GetStats(ctx context.Context) (DedupStats, error)

	// Maintenance
	Cleanup(ctx context.Context) error
	Close() error
}

// DedupStats represents deduplication statistics
type DedupStats struct {
	TotalFiles        int64
	UniqueFiles       int64
	TotalBlocks       int64
	UniqueBlocks      int64
	SavedSpace        int64
	TotalDataSize     int64
	DeduplicationRatio float64
	HashAlgorithm     string
	BlockSize         int64
}

// StorageUsage represents storage usage information
type StorageUsage struct {
	Size   int64
	Inodes int64
}

// BlockInfo represents block information
type BlockInfo struct {
	Hash      string
	Size      int64
	Offset    int64
	Reference int64
}

// Config represents deduplication engine configuration
type Config struct {
	Enabled          bool
	Algorithm        string // "file", "block", "both"
	BlockSize        int64
	MinFileSize      int64
	HashAlgorithm    string // "sha256", "blake3"
	Storage          types.StorageBackend
	ChunkingAlgorithm string // "fixed", "rabin", "buzhash"
	MinChunkSize     int64
	MaxChunkSize     int64
	AvgChunkSize     int64
}

// NewEngine creates a new deduplication engine
func NewEngine(config Config) (Engine, error) {
	if !config.Enabled {
		return NewNoOpEngine(), nil
	}

	switch config.Algorithm {
	case "file":
		return NewFileEngine(config)
	case "block":
		// Use the new advanced block deduplication engine
		return NewBlockDedupEngine(config)
	case "both":
		return NewHybridEngine(config)
	default:
		return nil, fmt.Errorf("unsupported deduplication algorithm: %s", config.Algorithm)
	}
}

// BaseEngine provides common functionality for all deduplication engines
type BaseEngine struct {
	config    Config
	storage   types.StorageBackend
	mu        sync.RWMutex
	stats     DedupStats
	refCount  map[string]int64 // Reference counting for garbage collection
	fileIndex map[string]string // Maps file paths to their hashes for tracking
}

// NewBaseEngine creates a new base deduplication engine
func NewBaseEngine(config Config) *BaseEngine {
	return &BaseEngine{
		config:    config,
		storage:   config.Storage,
		refCount:  make(map[string]int64),
		fileIndex: make(map[string]string),
		stats: DedupStats{
			HashAlgorithm: config.HashAlgorithm,
			BlockSize:     config.BlockSize,
		},
	}
}

// CreateHasher creates a hash based on the configured algorithm
func (e *BaseEngine) CreateHasher() hash.Hash {
	switch e.config.HashAlgorithm {
	case "sha256":
		return sha256.New()
	case "blake3":
		return blake3.New()
	default:
		return sha256.New() // Default to SHA-256
	}
}

// CalculateHash calculates hash for given data
func (e *BaseEngine) CalculateHash(data []byte) string {
	hasher := e.CreateHasher()
	hasher.Write(data)
	return hex.EncodeToString(hasher.Sum(nil))
}

// UpdateRefCount updates reference count for a hash
func (e *BaseEngine) UpdateRefCount(hash string, delta int64) {
	e.mu.Lock()
	defer e.mu.Unlock()

	e.refCount[hash] += delta
	if e.refCount[hash] <= 0 {
		delete(e.refCount, hash)
	}
}

// GetRefCount returns reference count for a hash
func (e *BaseEngine) GetRefCount(hash string) int64 {
	e.mu.RLock()
	defer e.mu.RUnlock()

	return e.refCount[hash]
}

// UpdateStats updates deduplication statistics
func (e *BaseEngine) UpdateStats(totalSize, savedSize int64, fileCount, blockCount int64) {
	e.mu.Lock()
	defer e.mu.Unlock()

	e.stats.TotalDataSize += totalSize
	e.stats.SavedSpace += savedSize
	e.stats.TotalFiles += fileCount
	e.stats.TotalBlocks += blockCount

	if e.stats.TotalDataSize > 0 {
		e.stats.DeduplicationRatio = float64(e.stats.SavedSpace) / float64(e.stats.TotalDataSize)
	}
}

// UpdateUniqueFiles updates the count of unique files
func (e *BaseEngine) UpdateUniqueFiles(delta int64) {
	e.mu.Lock()
	defer e.mu.Unlock()
	e.stats.UniqueFiles += delta
}

// FileEngine implements file-level deduplication
type FileEngine struct {
	*BaseEngine
}

// Ensure FileEngine implements Engine interface
var _ Engine = (*FileEngine)(nil)

// AddBlock adds a block (not implemented for file engine)
func (e *FileEngine) AddBlock(ctx context.Context, data []byte) (string, error) {
	return "", fmt.Errorf("block-level deduplication not supported in file engine")
}

// GetBlock retrieves a block (not implemented for file engine)
func (e *FileEngine) GetBlock(ctx context.Context, hash string) ([]byte, error) {
	return nil, fmt.Errorf("block-level deduplication not supported in file engine")
}

// DeleteBlock deletes a block (not implemented for file engine)
func (e *FileEngine) DeleteBlock(ctx context.Context, hash string) error {
	return fmt.Errorf("block-level deduplication not supported in file engine")
}

// BlockExists checks if a block exists (not implemented for file engine)
func (e *FileEngine) BlockExists(ctx context.Context, hash string) (bool, error) {
	return false, fmt.Errorf("block-level deduplication not supported in file engine")
}

// ProcessBlocks processes data into blocks (not implemented for file engine)
func (e *FileEngine) ProcessBlocks(ctx context.Context, data []byte) ([]BlockInfo, error) {
	return nil, fmt.Errorf("block-level deduplication not supported in file engine")
}

// ReconstructFile reconstructs a file from blocks (not implemented for file engine)
func (e *FileEngine) ReconstructFile(ctx context.Context, blocks []BlockInfo) ([]byte, error) {
	return nil, fmt.Errorf("block-level deduplication not supported in file engine")
}

// ProcessSnapshot processes a snapshot for deduplication
func (e *FileEngine) ProcessSnapshot(ctx context.Context, snapshotID string, path string) error {
	// For file engine, process each file individually
	return fmt.Errorf("not implemented")
}

// RemoveSnapshot removes a snapshot
func (e *FileEngine) RemoveSnapshot(ctx context.Context, snapshotID string) error {
	return nil
}

// GetSnapshotUsage returns snapshot usage information
func (e *FileEngine) GetSnapshotUsage(ctx context.Context, snapshotID string) (StorageUsage, error) {
	return StorageUsage{}, nil
}

// GetStats returns deduplication statistics
func (e *FileEngine) GetStats(ctx context.Context) (DedupStats, error) {
	return e.stats, nil
}

// Cleanup performs cleanup operations
func (e *FileEngine) Cleanup(ctx context.Context) error {
	return nil
}

// Close closes the file engine
func (e *FileEngine) Close() error {
	return nil
}

// NewFileEngine creates a new file-level deduplication engine
func NewFileEngine(config Config) (*FileEngine, error) {
	return &FileEngine{
		BaseEngine: NewBaseEngine(config),
	}, nil
}

// AddFile adds a file to the deduplication engine
func (e *FileEngine) AddFile(ctx context.Context, path string, data []byte) (string, error) {
	if int64(len(data)) < e.config.MinFileSize {
		// File too small for deduplication, store as-is
		return "", nil
	}

	hash := e.CalculateHash(data)

	// Check if file already exists
	exists, err := e.FileExists(ctx, hash)
	if err != nil {
		return "", fmt.Errorf("failed to check file existence: %w", err)
	}

	e.mu.Lock()
	defer e.mu.Unlock()

	// Track this file path
	e.fileIndex[path] = hash

	if !exists {
		// Store the file
		if err := e.storage.StoreFile(ctx, hash, data); err != nil {
			return "", fmt.Errorf("failed to store file: %w", err)
		}

		// Update statistics - new unique file
		e.stats.TotalDataSize += int64(len(data))
		e.stats.TotalFiles++
		e.stats.UniqueFiles++
	} else {
		// File already exists, update saved space
		e.stats.TotalDataSize += int64(len(data))
		e.stats.SavedSpace += int64(len(data))
		e.stats.TotalFiles++
	}

	// Update reference count
	e.refCount[hash]++

	// Update deduplication ratio
	if e.stats.TotalDataSize > 0 {
		e.stats.DeduplicationRatio = float64(e.stats.SavedSpace) / float64(e.stats.TotalDataSize)
	}

	return hash, nil
}

// GetFile retrieves a file from the deduplication engine
func (e *FileEngine) GetFile(ctx context.Context, hash string) ([]byte, error) {
	return e.storage.LoadFile(ctx, hash)
}

// DeleteFileByPath deletes a file from the deduplication engine by path
func (e *FileEngine) DeleteFileByPath(ctx context.Context, path string) error {
	e.mu.Lock()
	defer e.mu.Unlock()

	// Find the hash for this path
	hash, exists := e.fileIndex[path]
	if !exists {
		return nil // File path not tracked, nothing to delete
	}

	// Get file size for statistics
	data, err := e.storage.LoadFile(ctx, hash)
	if err != nil {
		return fmt.Errorf("failed to get file size: %w", err)
	}
	fileSize := int64(len(data))

	// Remove from file index
	delete(e.fileIndex, path)

	// Update reference count
	e.refCount[hash]--

	// If no more references, delete the file
	if e.refCount[hash] <= 0 {
		if err := e.storage.DeleteFile(ctx, hash); err != nil {
			return fmt.Errorf("failed to delete file: %w", err)
		}

		// Update statistics - remove one unique file
		e.stats.TotalFiles--
		e.stats.UniqueFiles--
	} else {
		// File still referenced, just reduce saved space
		e.stats.SavedSpace -= fileSize
		e.stats.TotalFiles--
	}

	// Update deduplication ratio
	if e.stats.TotalDataSize > 0 {
		e.stats.DeduplicationRatio = float64(e.stats.SavedSpace) / float64(e.stats.TotalDataSize)
	} else {
		e.stats.DeduplicationRatio = 0
	}

	return nil
}

// DeleteFile deletes a file from the deduplication engine
func (e *FileEngine) DeleteFile(ctx context.Context, hash string) error {
	// For backward compatibility, find a path with this hash and delete by path
	e.mu.RLock()
	var pathToDelete string
	for path, h := range e.fileIndex {
		if h == hash {
			pathToDelete = path
			break
		}
	}
	e.mu.RUnlock()

	if pathToDelete == "" {
		return nil // No path found with this hash
	}

	return e.DeleteFileByPath(ctx, pathToDelete)
}

// FileExists checks if a file exists in the deduplication engine
func (e *FileEngine) FileExists(ctx context.Context, hash string) (bool, error) {
	return e.storage.FileExists(ctx, hash)
}

// BlockEngine implements block-level deduplication
type BlockEngine struct {
	*BaseEngine
}

// Ensure BlockEngine implements Engine interface
var _ Engine = (*BlockEngine)(nil)

// AddFile adds a file (not implemented for block engine)
func (e *BlockEngine) AddFile(ctx context.Context, path string, data []byte) (string, error) {
	return "", fmt.Errorf("file-level deduplication not supported in block engine")
}

// GetFile retrieves a file (not implemented for block engine)
func (e *BlockEngine) GetFile(ctx context.Context, hash string) ([]byte, error) {
	return nil, fmt.Errorf("file-level deduplication not supported in block engine")
}

// DeleteFile deletes a file (not implemented for block engine)
func (e *BlockEngine) DeleteFile(ctx context.Context, hash string) error {
	return fmt.Errorf("file-level deduplication not supported in block engine")
}

// DeleteFileByPath deletes a file by path (not implemented for block engine)
func (e *BlockEngine) DeleteFileByPath(ctx context.Context, path string) error {
	return fmt.Errorf("file-level deduplication not supported in block engine")
}

// FileExists checks if a file exists (not implemented for block engine)
func (e *BlockEngine) FileExists(ctx context.Context, hash string) (bool, error) {
	return false, fmt.Errorf("file-level deduplication not supported in block engine")
}

// ProcessSnapshot processes a snapshot for deduplication
func (e *BlockEngine) ProcessSnapshot(ctx context.Context, snapshotID string, path string) error {
	// For block engine, process the entire snapshot as blocks
	return fmt.Errorf("not implemented")
}

// RemoveSnapshot removes a snapshot
func (e *BlockEngine) RemoveSnapshot(ctx context.Context, snapshotID string) error {
	return nil
}

// GetSnapshotUsage returns snapshot usage information
func (e *BlockEngine) GetSnapshotUsage(ctx context.Context, snapshotID string) (StorageUsage, error) {
	return StorageUsage{}, nil
}

// GetStats returns deduplication statistics
func (e *BlockEngine) GetStats(ctx context.Context) (DedupStats, error) {
	return e.stats, nil
}

// Cleanup performs cleanup operations
func (e *BlockEngine) Cleanup(ctx context.Context) error {
	return nil
}

// Close closes the block engine
func (e *BlockEngine) Close() error {
	return nil
}

// NewBlockEngine creates a new block-level deduplication engine
func NewBlockEngine(config Config) (*BlockEngine, error) {
	return &BlockEngine{
		BaseEngine: NewBaseEngine(config),
	}, nil
}

// AddBlock adds a block to the deduplication engine
func (e *BlockEngine) AddBlock(ctx context.Context, data []byte) (string, error) {
	if int64(len(data)) == 0 {
		return "", fmt.Errorf("empty block")
	}

	hash := e.CalculateHash(data)

	// Check if block already exists
	exists, err := e.BlockExists(ctx, hash)
	if err != nil {
		return "", fmt.Errorf("failed to check block existence: %w", err)
	}

	if !exists {
		// Store the block
		if err := e.storage.StoreBlock(ctx, hash, data); err != nil {
			return "", fmt.Errorf("failed to store block: %w", err)
		}

		// Update statistics
		e.UpdateStats(int64(len(data)), 0, 0, 1)
	} else {
		// Block already exists, update saved space
		e.UpdateStats(int64(len(data)), int64(len(data)), 0, 0)
	}

	// Update reference count
	e.UpdateRefCount(hash, 1)

	return hash, nil
}

// GetBlock retrieves a block from the deduplication engine
func (e *BlockEngine) GetBlock(ctx context.Context, hash string) ([]byte, error) {
	return e.storage.LoadBlock(ctx, hash)
}

// DeleteBlock deletes a block from the deduplication engine
func (e *BlockEngine) DeleteBlock(ctx context.Context, hash string) error {
	// Update reference count
	e.UpdateRefCount(hash, -1)

	// If no more references, delete the block
	if e.GetRefCount(hash) <= 0 {
		if err := e.storage.DeleteBlock(ctx, hash); err != nil {
			return fmt.Errorf("failed to delete block: %w", err)
		}

		// Update statistics
		e.UpdateStats(0, 0, 0, -1)
	}

	return nil
}

// BlockExists checks if a block exists in the deduplication engine
func (e *BlockEngine) BlockExists(ctx context.Context, hash string) (bool, error) {
	return e.storage.BlockExists(ctx, hash)
}

// ProcessBlocks processes data into blocks
func (e *BlockEngine) ProcessBlocks(ctx context.Context, data []byte) ([]BlockInfo, error) {
	var blocks []BlockInfo
	offset := int64(0)

	for offset < int64(len(data)) {
		blockSize := e.config.BlockSize
		if offset+blockSize > int64(len(data)) {
			blockSize = int64(len(data)) - offset
		}

		blockData := data[offset : offset+blockSize]
		hash := e.CalculateHash(blockData)

		// Add block to storage
		_, err := e.AddBlock(ctx, blockData)
		if err != nil {
			return nil, fmt.Errorf("failed to add block: %w", err)
		}

		blocks = append(blocks, BlockInfo{
			Hash:   hash,
			Size:   blockSize,
			Offset: offset,
		})

		offset += blockSize
	}

	return blocks, nil
}

// ReconstructFile reconstructs a file from blocks
func (e *BlockEngine) ReconstructFile(ctx context.Context, blocks []BlockInfo) ([]byte, error) {
	// Sort blocks by offset
	sortBlocks(blocks)

	var result []byte
	for _, block := range blocks {
		blockData, err := e.GetBlock(ctx, block.Hash)
		if err != nil {
			return nil, fmt.Errorf("failed to get block %s: %w", block.Hash, err)
		}
		result = append(result, blockData...)
	}

	return result, nil
}

// HybridEngine implements both file-level and block-level deduplication
type HybridEngine struct {
	fileEngine  *FileEngine
	blockEngine *BlockEngine
	config      Config
}

// Ensure HybridEngine implements Engine interface
var _ Engine = (*HybridEngine)(nil)

// NewHybridEngine creates a new hybrid deduplication engine
func NewHybridEngine(config Config) (*HybridEngine, error) {
	fileEngine, err := NewFileEngine(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create file engine: %w", err)
	}

	blockEngine, err := NewBlockEngine(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create block engine: %w", err)
	}

	return &HybridEngine{
		fileEngine:  fileEngine,
		blockEngine: blockEngine,
		config:      config,
	}, nil
}

// AddFile adds a file using hybrid deduplication
func (e *HybridEngine) AddFile(ctx context.Context, path string, data []byte) (string, error) {
	if int64(len(data)) < e.config.MinFileSize {
		// File too small, don't deduplicate
		return "", nil
	}

	// Try file-level deduplication first
	fileHash, err := e.fileEngine.AddFile(ctx, path, data)
	if err != nil {
		return "", fmt.Errorf("failed to add file to file engine: %w", err)
	}

	// Also process blocks for potential cross-file deduplication
	_, err = e.blockEngine.ProcessBlocks(ctx, data)
	if err != nil {
		// Log error but don't fail the operation
		fmt.Printf("Warning: failed to process blocks: %v\n", err)
	}

	return fileHash, nil
}

// GetFile retrieves a file using hybrid deduplication
func (e *HybridEngine) GetFile(ctx context.Context, hash string) ([]byte, error) {
	// Try file-level retrieval first
	data, err := e.fileEngine.GetFile(ctx, hash)
	if err == nil {
		return data, nil
	}

	// If file-level fails, try block-level reconstruction
	// This would require additional metadata to know which blocks belong to the file
	return nil, fmt.Errorf("file not found: %w", err)
}

// DeleteFile deletes a file using hybrid deduplication
func (e *HybridEngine) DeleteFile(ctx context.Context, hash string) error {
	// Delete from file engine
	if err := e.fileEngine.DeleteFile(ctx, hash); err != nil {
		return fmt.Errorf("failed to delete file from file engine: %w", err)
	}

	// Note: Block cleanup should be handled separately by garbage collection
	// to avoid deleting blocks that might be referenced by other files

	return nil
}

// DeleteFileByPath deletes a file by path using hybrid deduplication
func (e *HybridEngine) DeleteFileByPath(ctx context.Context, path string) error {
	// Delete from file engine
	if err := e.fileEngine.DeleteFileByPath(ctx, path); err != nil {
		return fmt.Errorf("failed to delete file from file engine: %w", err)
	}

	return nil
}

// FileExists checks if a file exists
func (e *HybridEngine) FileExists(ctx context.Context, hash string) (bool, error) {
	return e.fileEngine.FileExists(ctx, hash)
}

// AddBlock adds a block
func (e *HybridEngine) AddBlock(ctx context.Context, data []byte) (string, error) {
	return e.blockEngine.AddBlock(ctx, data)
}

// GetBlock retrieves a block
func (e *HybridEngine) GetBlock(ctx context.Context, hash string) ([]byte, error) {
	return e.blockEngine.GetBlock(ctx, hash)
}

// DeleteBlock deletes a block
func (e *HybridEngine) DeleteBlock(ctx context.Context, hash string) error {
	return e.blockEngine.DeleteBlock(ctx, hash)
}

// BlockExists checks if a block exists
func (e *HybridEngine) BlockExists(ctx context.Context, hash string) (bool, error) {
	return e.blockEngine.BlockExists(ctx, hash)
}

// ProcessBlocks processes data into blocks
func (e *HybridEngine) ProcessBlocks(ctx context.Context, data []byte) ([]BlockInfo, error) {
	return e.blockEngine.ProcessBlocks(ctx, data)
}

// ReconstructFile reconstructs a file from blocks
func (e *HybridEngine) ReconstructFile(ctx context.Context, blocks []BlockInfo) ([]byte, error) {
	return e.blockEngine.ReconstructFile(ctx, blocks)
}

// ProcessSnapshot processes a snapshot for deduplication
func (e *HybridEngine) ProcessSnapshot(ctx context.Context, snapshotID string, path string) error {
	// Walk through all files in the snapshot
	err := filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		// Read file data
		data, err := os.ReadFile(filePath)
		if err != nil {
			return fmt.Errorf("failed to read file %s: %w", filePath, err)
		}

		// Add file to deduplication engine
		relativePath, err := filepath.Rel(path, filePath)
		if err != nil {
			return fmt.Errorf("failed to get relative path: %w", err)
		}

		_, err = e.AddFile(ctx, relativePath, data)
		if err != nil {
			return fmt.Errorf("failed to add file %s: %w", relativePath, err)
		}

		return nil
	})

	return err
}

// RemoveSnapshot removes a snapshot
func (e *HybridEngine) RemoveSnapshot(ctx context.Context, snapshotID string) error {
	// For now, just log the removal
	// Actual cleanup should be handled by garbage collection
	fmt.Printf("Removing snapshot: %s\n", snapshotID)
	return nil
}

// GetSnapshotUsage returns snapshot usage information
func (e *HybridEngine) GetSnapshotUsage(ctx context.Context, snapshotID string) (StorageUsage, error) {
	// For now, return dummy usage
	// This should be implemented with proper tracking
	return StorageUsage{
		Size:   0,
		Inodes: 0,
	}, nil
}

// GetStats returns deduplication statistics
func (e *HybridEngine) GetStats(ctx context.Context) (DedupStats, error) {
	fileStats, err := e.fileEngine.GetStats(ctx)
	if err != nil {
		return DedupStats{}, fmt.Errorf("failed to get file stats: %w", err)
	}

	blockStats, err := e.blockEngine.GetStats(ctx)
	if err != nil {
		return DedupStats{}, fmt.Errorf("failed to get block stats: %w", err)
	}

	// Combine statistics
	return DedupStats{
		TotalFiles:         fileStats.TotalFiles,
		UniqueFiles:        fileStats.UniqueFiles,
		TotalBlocks:        blockStats.TotalBlocks,
		UniqueBlocks:       blockStats.UniqueBlocks,
		SavedSpace:         fileStats.SavedSpace + blockStats.SavedSpace,
		TotalDataSize:      fileStats.TotalDataSize + blockStats.TotalDataSize,
		DeduplicationRatio: (fileStats.DeduplicationRatio + blockStats.DeduplicationRatio) / 2,
		HashAlgorithm:      e.config.HashAlgorithm,
		BlockSize:          e.config.BlockSize,
	}, nil
}

// Cleanup performs cleanup operations
func (e *HybridEngine) Cleanup(ctx context.Context) error {
	if err := e.fileEngine.Cleanup(ctx); err != nil {
		return fmt.Errorf("failed to cleanup file engine: %w", err)
	}

	if err := e.blockEngine.Cleanup(ctx); err != nil {
		return fmt.Errorf("failed to cleanup block engine: %w", err)
	}

	return nil
}

// Close closes the deduplication engine
func (e *HybridEngine) Close() error {
	// No specific cleanup needed for hybrid engine
	return nil
}

// NoOpEngine is a no-operation deduplication engine
type NoOpEngine struct{}

// Ensure NoOpEngine implements Engine interface
var _ Engine = (*NoOpEngine)(nil)

// NewNoOpEngine creates a new no-operation deduplication engine
func NewNoOpEngine() *NoOpEngine {
	return &NoOpEngine{}
}

func (e *NoOpEngine) AddFile(ctx context.Context, path string, data []byte) (string, error) {
	return "", nil
}

func (e *NoOpEngine) GetFile(ctx context.Context, hash string) ([]byte, error) {
	return nil, types.ErrDedupNotFound
}

func (e *NoOpEngine) DeleteFile(ctx context.Context, hash string) error {
	return nil
}

func (e *NoOpEngine) DeleteFileByPath(ctx context.Context, path string) error {
	return nil
}

func (e *NoOpEngine) FileExists(ctx context.Context, hash string) (bool, error) {
	return false, nil
}

func (e *NoOpEngine) AddBlock(ctx context.Context, data []byte) (string, error) {
	return "", nil
}

func (e *NoOpEngine) GetBlock(ctx context.Context, hash string) ([]byte, error) {
	return nil, types.ErrDedupNotFound
}

func (e *NoOpEngine) DeleteBlock(ctx context.Context, hash string) error {
	return nil
}

func (e *NoOpEngine) BlockExists(ctx context.Context, hash string) (bool, error) {
	return false, nil
}

func (e *NoOpEngine) ProcessBlocks(ctx context.Context, data []byte) ([]BlockInfo, error) {
	return nil, nil
}

func (e *NoOpEngine) ReconstructFile(ctx context.Context, blocks []BlockInfo) ([]byte, error) {
	return nil, nil
}

func (e *NoOpEngine) ProcessSnapshot(ctx context.Context, snapshotID string, path string) error {
	return nil
}

func (e *NoOpEngine) RemoveSnapshot(ctx context.Context, snapshotID string) error {
	return nil
}

func (e *NoOpEngine) GetSnapshotUsage(ctx context.Context, snapshotID string) (StorageUsage, error) {
	return StorageUsage{}, nil
}

func (e *NoOpEngine) GetStats(ctx context.Context) (DedupStats, error) {
	return DedupStats{}, nil
}

func (e *NoOpEngine) Cleanup(ctx context.Context) error {
	return nil
}

func (e *NoOpEngine) Close() error {
	return nil
}

// Helper functions

func sortBlocks(blocks []BlockInfo) {
	// Simple bubble sort for blocks by offset
	for i := 0; i < len(blocks); i++ {
		for j := i + 1; j < len(blocks); j++ {
			if blocks[i].Offset > blocks[j].Offset {
				blocks[i], blocks[j] = blocks[j], blocks[i]
			}
		}
	}
}